/*
一个简单定时器的实现

定时器的主要实现的功能：
1.最近触发的定时任务距离当前还要多久
2.获取当前时间的接口
3.删除定时器
4.添加定时器
5.检查（执行）定时器的任务

参考链接：B站 BV1md4y1U7Ne
*/


#include <sys/epoll.h>
#include <unistd.h>

#include <iostream>
#include <chrono>
#include <functional>
#include <set>
#include <memory>


struct TimerNodeBase
{
    time_t   expire;//到期时间
    int64_t  id;    //定时器的唯一标识
};

//定时器节点
struct TimerNode : public TimerNodeBase
{
    using CallBack = std::function<void(const TimerNode& node)>;
    CallBack func;  //回调方法
};


//使用C++14的特性，减少丢func的拷贝
bool operator<(const TimerNodeBase& lNode, const TimerNodeBase& rNode)
{
    if(lNode.expire < rNode.expire)
    {
        return true;
    }
    else if(lNode.expire > rNode.expire)
    {
        return false;
    }
    return lNode.id < rNode.id; //如果expire相等，就使用id排序
}


class Timer
{
public:
    //获取当前时间（ms）
    static time_t GetTick()
    {
        //std::chrono::steady_clock::now() //系统启动以来的稳定时间点，不受其他因素的影响。
        //time_point_cast<...> 这是一个时间点转换的函数,它将一个时间点转换为另一个时间点，但保留了原始时间点的精度
        auto sc = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now());
        //duration_cast<...> 时间段（duration）的转换函数，它将一个时间段转换为另一个时间段，但保留了原始时间段的精度
        //这里表示获取系统启动以来的稳定时间点到调用std::chrono::steady_clock::now()的时间点的时间间隔
        auto temp = std::chrono::duration_cast<std::chrono::milliseconds> (sc.time_since_epoch());
        return temp.count();
    }

    //生成定时器id
    static uint64_t GetId()
    {
        return ++_id;
    }

    /*
        添加定时器
        msec: 定时时间
        func: 回调函数
    */
    TimerNodeBase AddTimer(time_t msec, TimerNode::CallBack func)
    {
        TimerNode tonde;
        tonde.expire = GetTick() + msec;
        tonde.func = func;
        tonde.id = GetId();

        timerMap.insert(tonde);
        return static_cast<TimerNodeBase>(tonde);
    }

    //删除定时器
    bool DelTimer(TimerNodeBase& node)
    {
        auto iter = timerMap.find(node);
        if(iter != timerMap.end())
        {
            timerMap.erase(iter);
            return true;
        }
        return false;
    }

    //执行超时的任务
    bool CheckTimer()
    {
        auto iter = timerMap.begin();
        if(iter != timerMap.end() && iter->expire <= GetTick())
        {
            iter->func(*iter);
            timerMap.erase(iter);
            return true;
        }

        return false;
    }

    //获取最近一个定时器任务的超时时间
    time_t TimerToSleep()
    {
        auto iter = timerMap.begin();
        if(iter ==  timerMap.end())
        {
            return -1; //当没有任务时，就让epoll_waite阻塞等待
        }

        time_t diss = iter->expire - GetTick();
        return diss > 0 ? diss : 0;
    }

    uint32_t GetTimerNum()
    {
        return timerMap.size();
    }
private:
    static int64_t _id;           //定时任务的id
    std::set<TimerNode, std::less<>> timerMap; //定时器容器
};
int64_t Timer::_id = 0;



void TestTimer()
{
    std::unique_ptr<Timer> timer = std::make_unique<Timer>();

    timer->AddTimer(1000, [](const TimerNode& node){
        std::cout << "node id: " << node.id << std::endl;
        std::cout << "expire: " << node.expire << std::endl;
    });

    timer->AddTimer(1000, [](const TimerNode& node){
        std::cout << "node id: " << node.id << std::endl;
        std::cout << "expire: " << node.expire << std::endl;
    });

    auto node = timer->AddTimer(1000, [](const TimerNode& node){
        std::cout << "node id: " << node.id << std::endl;
        std::cout << "expire: " << node.expire << std::endl;
    });

    timer->DelTimer(node);

    sleep(1);

    while(timer->CheckTimer());
}

int main(void)
{
    // TestTimer();
    // return 0;

    std::unique_ptr<Timer> timer = std::make_unique<Timer>();

    int epfd = epoll_create(1);
    epoll_event ev[64] = {0};

    while(true)
    {
        int rt = epoll_wait(epfd, ev, 64, timer->TimerToSleep());
        
        for(int i = 0; i < rt; ++i)
        {
            //处理各种事件
        }

        //执行超时任务
        while(timer->CheckTimer());
    }

    return 0;
}
